package br.com.virtual.recomendar.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import br.com.virtual.base.uteis.VirtualConstants;
import br.com.virtual.cadastrar.model.Pessoa;
import br.com.virtual.cadastrar.model.Produto;
import br.com.virtual.recomendar.comparator.PessoaSemelhanteComparator;
import br.com.virtual.recomendar.model.Avaliacao;
import br.com.virtual.recomendar.service.LocalizadorPessoasSemelhantes;

public class LocalizadorPessoasSemelhantesImpl implements
		LocalizadorPessoasSemelhantes, VirtualConstants {
	
	Pessoa cliente;
	List<Pessoa> pessoasComparadas;
	Integer resultadoMaximo;
	

	public LocalizadorPessoasSemelhantesImpl(Pessoa cliente,
			List<Pessoa> pessoasComparadas) {
		
		this.cliente = cliente;
		this.pessoasComparadas = pessoasComparadas;
		this.resultadoMaximo = NUMERO_DE_SEMELHANTES;
		
	}

	
	/*
	 * Pessoa cliente,
			List<Avaliacao> avaliacoesCliente,
			Map<Pessoa, List<Avaliacao>> candidatosASemelhantes
	 * */
	
	@Override
	public Map<Pessoa, Float> listarSemelhantes( ) {
		
		return listarSemelhantes(resultadoMaximo);
	}
	
	
	@Override
	public Map<Pessoa, Float> listarSemelhantes(Integer numeroSemelhantesRetornar ) {

		this.resultadoMaximo = numeroSemelhantesRetornar;
		Map<Pessoa, Float> semelhantes = new TreeMap<Pessoa, Float>();

		if (pessoasComparadas.size() > 0) {
			for (Pessoa candidato : pessoasComparadas) {

				Map<Produto, Avaliacao> produtosAvaliadosCandidato = getProdutosAvaliadosCandidato(candidato.getAvaliacoes());
				
				semelhantes.put(
						candidato,
						calculaSemelhanca(cliente.getAvaliacoes(),
								produtosAvaliadosCandidato));
			}
		}

		Map<Pessoa, Float> sorted = new TreeMap<Pessoa, Float>(new PessoaSemelhanteComparator(semelhantes));
		sorted.putAll(semelhantes);
		
//		if( sorted.size() > this.resultadoMaximo){
//			
//			List<Pessoa> pessoasSimilares = new LinkedList<Pessoa>(sorted.keySet());
//			
//			for(int i = this.resultadoMaximo; i < pessoasSimilares.size(); i++ ){
//				
//				Pessoa pessoaRemover = pessoasSimilares.get(i);
//				sorted.remove(pessoaRemover);
//			}
//		}
		
		return semelhantes;
	}

	private Float calculaSemelhanca(List<Avaliacao> avaliacoesCliente,
			Map<Produto, Avaliacao> produtosAvaliadosCandidato) {

		Float avaliacaoFinalCliente = new Float(0.0);
		
		for (Avaliacao avaliacao : avaliacoesCliente) {

			Float notaCliente, notaCandidato;

			notaCliente = avaliacao.getNota();
			Produto produtoAvaliadoCliente = avaliacao.getProduto();

			notaCandidato = ((produtosAvaliadosCandidato.containsKey(produtoAvaliadoCliente)) 
					? produtosAvaliadosCandidato.get(produtoAvaliadoCliente).getNota()
					: 0F);

					
			avaliacaoFinalCliente += (float) Math.pow((notaCliente - notaCandidato), 2);
		}

		avaliacaoFinalCliente = 1 / (1 + (float)Math.sqrt(avaliacaoFinalCliente));
		
		return avaliacaoFinalCliente;
	}

	private Map<Produto, Avaliacao> getProdutosAvaliadosCandidato(
			List<Avaliacao> avaliacoesCandidato) {

		Map<Produto, Avaliacao> produtosAvaliadosCandidato = new HashMap<Produto, Avaliacao>();
		for (Avaliacao avaliacaoCandato : avaliacoesCandidato) {
			produtosAvaliadosCandidato.put(avaliacaoCandato.getProduto(),
					avaliacaoCandato);
		}

		return produtosAvaliadosCandidato;
	}

}
